//! # Axum 中间件集成
//!
//! 为 Axum Web 框架提供认证授权中间件

use super::{MiddlewareConfig, MiddlewareError};
use crate::service::AuthService;
use axum::{
    extract::{Request, State},
    http::{HeaderMap, Method, StatusCode, Uri},
    middleware::Next,
    response::Response,
};
use rustcloud_security::prelude::*;
use std::collections::HashMap;
use std::sync::Arc;
use tower::{Layer, Service};
use tower_layer::Identity;

/// 认证中间件
#[derive(Clone)]
pub struct AuthMiddleware {
    auth_service: Arc<AuthService>,
    config: MiddlewareConfig,
}

/// 认证层
#[derive(Clone)]
pub struct AuthLayer {
    auth_service: Arc<AuthService>,
    config: MiddlewareConfig,
}

/// 认证信息提取器
pub struct AuthExtractor {
    /// 认证主体
    pub principal: Option<Principal>,
    /// 认证上下文
    pub context: AuthContext,
}

impl AuthMiddleware {
    /// 创建新的认证中间件
    pub fn new(auth_service: Arc<AuthService>, config: MiddlewareConfig) -> Self {
        Self {
            auth_service,
            config,
        }
    }

    /// 处理请求
    pub async fn handle(
        &self,
        uri: Uri,
        method: Method,
        headers: HeaderMap,
        mut request: Request,
        next: Next,
    ) -> Result<Response, MiddlewareError> {
        let path = uri.path().to_string();
        
        // 检查是否跳过认证
        if self.should_skip_auth(&path) {
            return Ok(next.run(request).await);
        }

        // 构建认证上下文
        let context = self.build_auth_context(&method, &path, &headers)?;
        
        // 执行认证
        let principal = match self.auth_service.authenticate(&context).await {
            Ok(principal) => Some(principal),
            Err(err) => {
                if self.is_optional_auth(&path) {
                    None
                } else {
                    return Err(MiddlewareError::AuthenticationFailed(err.to_string()));
                }
            }
        };

        // 如果有认证主体，执行授权检查
        if let Some(ref principal) = principal {
            let resource = Resource::new(
                self.extract_service_name(&path),
                path.clone(),
                method.to_string(),
            );

            match self.auth_service.authorize(principal, &resource).await {
                Ok(result) if result.authorized => {
                    // 授权成功，继续处理请求
                },
                Ok(_) => {
                    return Err(MiddlewareError::AuthorizationFailed(
                        "Access denied".to_string()
                    ));
                },
                Err(err) => {
                    return Err(MiddlewareError::AuthorizationFailed(err.to_string()));
                }
            }
        }

        // 将认证信息添加到请求扩展中
        request.extensions_mut().insert(AuthExtractor {
            principal,
            context,
        });

        Ok(next.run(request).await)
    }

    /// 检查是否应该跳过认证
    fn should_skip_auth(&self, path: &str) -> bool {
        self.config.skip_paths.iter().any(|skip_path| {
            path.starts_with(skip_path)
        })
    }

    /// 检查是否为可选认证
    fn is_optional_auth(&self, path: &str) -> bool {
        self.config.optional_paths.iter().any(|optional_path| {
            path.starts_with(optional_path)
        })
    }

    /// 构建认证上下文
    fn build_auth_context(
        &self,
        method: &Method,
        path: &str,
        headers: &HeaderMap,
    ) -> Result<AuthContext, MiddlewareError> {
        let mut context_headers = HashMap::new();
        
        // 提取常用头部
        if let Some(auth_header) = headers.get("authorization") {
            if let Ok(auth_str) = auth_header.to_str() {
                context_headers.insert("authorization".to_string(), auth_str.to_string());
            }
        }

        if let Some(user_agent) = headers.get("user-agent") {
            if let Ok(ua_str) = user_agent.to_str() {
                context_headers.insert("user-agent".to_string(), ua_str.to_string());
            }
        }

        if let Some(session_id) = headers.get("x-session-id") {
            if let Ok(session_str) = session_id.to_str() {
                context_headers.insert("session-id".to_string(), session_str.to_string());
            }
        }

        // 提取客户端IP（从代理头部或连接信息）
        let client_ip = headers
            .get("x-forwarded-for")
            .or_else(|| headers.get("x-real-ip"))
            .and_then(|ip| ip.to_str().ok())
            .map(|ip| ip.split(',').next().unwrap_or(ip).trim().to_string());

        Ok(AuthContext::new(
            context_headers,
            method.to_string(),
            path.to_string(),
            client_ip,
        ))
    }

    /// 从路径提取服务名称
    fn extract_service_name(&self, path: &str) -> String {
        // 简单的服务名称提取逻辑
        // 假设路径格式为 /api/service-name/...
        let parts: Vec<&str> = path.trim_start_matches('/').split('/').collect();
        if parts.len() >= 2 && parts[0] == "api" {
            parts[1].to_string()
        } else {
            "unknown".to_string()
        }
    }
}

impl AuthLayer {
    /// 创建新的认证层
    pub fn new(auth_service: Arc<AuthService>, config: MiddlewareConfig) -> Self {
        Self {
            auth_service,
            config,
        }
    }
}

impl<S> Layer<S> for AuthLayer {
    type Service = AuthMiddleware;

    fn layer(&self, _inner: S) -> Self::Service {
        AuthMiddleware::new(self.auth_service.clone(), self.config.clone())
    }
}

// Axum 中间件函数
pub async fn auth_middleware(
    State(auth_service): State<Arc<AuthService>>,
    uri: Uri,
    method: Method,
    headers: HeaderMap,
    request: Request,
    next: Next,
) -> Result<Response, StatusCode> {
    let config = MiddlewareConfig::default();
    let middleware = AuthMiddleware::new(auth_service, config);
    
    match middleware.handle(uri, method, headers, request, next).await {
        Ok(response) => Ok(response),
        Err(MiddlewareError::AuthenticationFailed(_)) => Err(StatusCode::UNAUTHORIZED),
        Err(MiddlewareError::AuthorizationFailed(_)) => Err(StatusCode::FORBIDDEN),
        Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
    }
}

// Axum 提取器实现
#[axum::async_trait]
impl<S> axum::extract::FromRequestParts<S> for AuthExtractor
where
    S: Send + Sync,
{
    type Rejection = StatusCode;

    async fn from_request_parts(
        parts: &mut axum::http::request::Parts,
        _state: &S,
    ) -> Result<Self, Self::Rejection> {
        parts
            .extensions
            .get::<AuthExtractor>()
            .cloned()
            .ok_or(StatusCode::INTERNAL_SERVER_ERROR)
    }
}

impl Clone for AuthExtractor {
    fn clone(&self) -> Self {
        Self {
            principal: self.principal.clone(),
            context: self.context.clone(),
        }
    }
}

/// 辅助宏，用于创建需要认证的路由
#[macro_export]
macro_rules! authenticated_route {
    ($method:ident, $path:expr, $handler:expr) => {
        axum::routing::$method($path, $handler)
            .layer(axum::middleware::from_fn_with_state(
                auth_service.clone(),
                auth_middleware,
            ))
    };
}

/// 辅助宏，用于创建需要特定权限的路由
#[macro_export]
macro_rules! authorized_route {
    ($method:ident, $path:expr, $handler:expr, $permission:expr) => {
        axum::routing::$method($path, $handler)
            .layer(axum::middleware::from_fn_with_state(
                auth_service.clone(),
                auth_middleware,
            ))
            // TODO: 添加权限检查中间件
    };
}